/*blinker*/
#define BLINKER_WIFI
#define BLINKER_ESP_TASK
#define BLINKER_ESP_SMARTCONFIG
// #define BLINKER_WITHOUT_SSL
#ifdef TEMP_AND_HUMI_FUNCTION
    #define BLINKER_MIOT_SENSOR
#else
    #define BLINKER_MIOT_LIGHT
#endif

#include <Blinker.h>
#include "OneButton.h"

#define BLINKER_BUTTON_PIN 9
// button trigged when pin input level is LOW
OneButton button(BLINKER_BUTTON_PIN, true);

#error
char auth[] = "";   //填入Blinker 密钥 

#include "config.h"
#include "font.h"
#include <SPI.h>
#include <Ticker.h>
#include <time.h>
Ticker tckr;



/*温湿度*/
#ifdef TEMP_AND_HUMI_FUNCTION
    BlinkerNumber HUMI("humi");
    BlinkerNumber TEMP("temp");
#endif
/*光线*/
BlinkerText Lux("Lux");


/*开关*/
BlinkerButton Lamp("Lamp");

/*硬件*/
bool Connected_fl = 0;
bool Connected_st = 0;
bool ScreenPower_st = 1;
uint8_t GuiNum = 0;



void attachClick()
{
  	Serial.println("click-单击");
    // OLED_Clear();
    GuiNum++;
    if(GuiNum > 3)  GuiNum = 1;
}

void Set_Time(void*arg)
{
    while(1){
        while ((WiFi.status() != WL_CONNECTED) /*&& (Connected_fl == 0)*/) {
            printf("Connecting to Wi-Fi... \r\n");
            Connected_fl = 0;
            if(Fade_auto){
                LED_1.LEDC_Fade();
            }
            else {
                LED_1.LEDC_FadeStop();
                vTaskDelay(1000 / portTICK_PERIOD_MS);
            }

        }
        LED_1.LEDC_FadeStop();

        printf("Getting NTP Time...\r\n");
        Connected_fl = 1;   
        

        if(Blinker.hour() != -1){
            rtc.setTime((uint8_t)Blinker.hour(), (uint8_t)Blinker.minute(), (uint8_t)Blinker.second());
            printf("Get Blinker NTP Time: %d:%d:%d\r\n", Blinker.hour(), Blinker.minute(), Blinker.second());

            rtc.setDate((uint8_t)Blinker.mday(), (uint8_t)Blinker.wday(), (uint8_t)Blinker.month(), 0, (uint8_t)(Blinker.year()-2000));
            printf("Get Blinker NTP Date: %d.%d.%d   WeekDay: %d\r\n", Blinker.year(), Blinker.month(), Blinker.mday(),Blinker.wday());

            // Connected_fl = 1;   
                
            Lamp_auto = 1;

            vTaskDelete( NULL );
        }
        else{
            vTaskDelay(1000/portTICK_RATE_MS);
        }
        
    }
}

/*==========================================Blinker==========================================*/

void deviceReset()
{
    Blinker.reset();
}

void dataRead(const String & data)
{
    BLINKER_LOG("Blinker readString: ", data);

    Blinker.vibrate();
    
    uint32_t BlinkerTime = millis();
    
    Blinker.print("millis", BlinkerTime);
}

/**
 * @brief Blinker周期上报
 * 
 */
void heartbeat()
{

#ifdef TEMP_AND_HUMI_FUNCTION
    HUMI.print(SHT30.Humi);
    TEMP.print(SHT30.Temp);
#endif
    /*灯*/
    if(Button1_flag){
        Lamp.icon("fas fa-lightbulb-on");
        Lamp.print("on");
    }else if(!Button1_flag){
        Lamp.icon("far fa-lightbulb-slash");
        Lamp.print("off");
    }
    Lamp.text("灯");

    /*光强*/
    if(ADC_Light.Level == 1) {
        Lux.print("弱");
        Lux.color("#5F9EA0");
    }
    else if(ADC_Light.Level == 2) {
        Lux.print("中");
        Lux.color("#FF8C00");
    }
    else if(ADC_Light.Level == 3) {
        Lux.print("强");
        Lux.color("#FFD700");
    }
}

void dataStorage()
{
#ifdef TEMP_AND_HUMI_FUNCTION
    Blinker.dataStorage("temp", SHT30.Temp);
    Blinker.dataStorage("humi", SHT30.Humi);
#endif
}

/**
 * @brief 小爱同学
 * 
 * @param queryCode 
 */
#ifdef TEMP_AND_HUMI_FUNCTION
void miotQuery(int32_t queryCode)
{
    BLINKER_LOG("MIOT Query codes: ", queryCode);

    switch (queryCode)
    {
        case BLINKER_CMD_QUERY_ALL_NUMBER :
            BLINKER_LOG("MIOT Query All");
            BlinkerMIOT.temp(SHT30.Temp);
            BlinkerMIOT.humi(SHT30.Humi);
            BlinkerMIOT.print();
            break;
        default :
            BlinkerMIOT.temp(20);
            BlinkerMIOT.humi(20);
            break;
    }
}

#else
void miotPowerState(const String & state)
{
    BLINKER_LOG("need set power state: ", state);

    Lamp_auto = 0;
    if (state == BLINKER_CMD_ON) {
        Button1_flag = 1;

        BlinkerMIOT.powerState("on");
        BlinkerMIOT.print();
    }
    else if (state == BLINKER_CMD_OFF) {
        Button1_flag = 0;
        BlinkerMIOT.powerState("off");
        BlinkerMIOT.print();
    }
}
#endif


/**
 * @brief 灯光回调
 * 
 * @param state 
 */
void Lamp_callback(const String & state)
{
    BLINKER_LOG("get Lamp state: ", state);
    Lamp_auto = 0;
    if(state == "on"){
        Button1_flag = 1;
        Lamp.icon("fas fa-lightbulb-on");
        Lamp.print("on");
    }
    else if(state == "off"){
        Button1_flag = 0;
        Lamp.icon("far fa-lightbulb-slash");
        Lamp.print("off");
    }
    
    Lamp.text("灯");
}

/*==========================================Display==========================================*/
unsigned short maxPosX = anzMAX * 8 - 1;            
unsigned short LEDarr[anzMAX][8];                   
unsigned short helpArrMAX[anzMAX * 8];              
unsigned short helpArrPos[anzMAX * 8];              
unsigned int z_PosX = 0;                            
unsigned int d_PosX = 0;                            
bool f_tckr1s = false;
bool f_tckr50ms = false;

//*************************************************************************************************
const unsigned short InitArr[7][2] = { { 0x0C, 0x00 },    // display off
        { 0x00, 0xFF },    // no LEDtest
        { 0x09, 0x00 },    // BCD off
        { 0x0F, 0x00 },    // normal operation
        { 0x0B, 0x07 },    // start display
        { 0x0A, 0x04 },    // brightness
        { 0x0C, 0x01 }     // display on
};


void max7219_init()  //all MAX7219 init
{
    ScreenPower.LED_On();
    vTaskDelay(30 / portTICK_PERIOD_MS);
    
    unsigned short i, j;
    for (i = 0; i < 7; i++) {
        digitalWrite(CS, LOW);
        delayMicroseconds(1);
        for (j = 0; j < anzMAX; j++) {
            SPI.write(InitArr[i][0]);  //register
            SPI.write(InitArr[i][1]);  //value
        }
        digitalWrite(CS, HIGH);
    }
}

void max7219_power_off()
{
    ScreenPower.LED_Off();
    ScreenPower_st = 0;
}
//**************************************************************************************************
void max7219_set_brightness(unsigned short br)  //brightness MAX7219
{
    unsigned short j;
    if (br < 16) {
        digitalWrite(CS, LOW);
        delayMicroseconds(1);
        for (j = 0; j < anzMAX; j++) {
            SPI.write(0x0A);  //register
            SPI.write(br);    //value
        }
        digitalWrite(CS, HIGH);
    }
}
//**************************************************************************************************
void helpArr_init(void)  //helperarray init
{
    unsigned short i, j, k;
    j = 0;
    k = 0;
    for (i = 0; i < anzMAX * 8; i++) {
        helpArrPos[i] = (1 << j);   //bitmask
        helpArrMAX[i] = k;
        j++;
        if (j > 7) {
            j = 0;
            k++;
        }
    }
}
//**************************************************************************************************
void clear_Display()   //clear all
{
    unsigned short i, j;
    for (i = 0; i < 8; i++)     //8 rows
    {
        digitalWrite(CS, LOW);
        delayMicroseconds(1);
        for (j = anzMAX; j > 0; j--) {
            LEDarr[j - 1][i] = 0;       //LEDarr clear
            SPI.write(i + 1);           //current row
            SPI.write(LEDarr[j - 1][i]);
        }
        digitalWrite(CS, HIGH);
    }
}
//*********************************************************************************************************
void rotate_90() // for Generic displays
{
    for (uint8_t k = anzMAX; k > 0; k--) {

        uint8_t i, j, m, imask, jmask;
        uint8_t tmp[8]={0,0,0,0,0,0,0,0};
        for (  i = 0, imask = 0x80; i < 8; i++, imask >>= 1) {
          for (j = 0, jmask = 0x80; j < 8; j++, jmask >>= 1) {
            if (LEDarr[k-1][i] & jmask) {
              tmp[j] |= imask;
            }
          }
        }
        for(m=0; m<8; m++){
            LEDarr[k-1][m]=tmp[m];
        }
    }
}
//**************************************************************************************************
void refresh_display() //take info into LEDarr
{
    unsigned short i, j;

#ifdef ROTATE_90
    rotate_90();
#endif

    for (i = 0; i < 8; i++)     //8 rows
    {
        digitalWrite(CS, LOW);
        delayMicroseconds(1);
        for (j = 1; j <= anzMAX; j++) {
            SPI.write(i + 1);  //current row
            
#ifdef REVERSE_HORIZONTAL
            SPI.setBitOrder(LSBFIRST);      // bitorder for reverse columns
#endif

#ifdef REVERSE_VERTICAL
            SPI.write(LEDarr[j - 1][7-i]);
#else
            SPI.write(LEDarr[j - 1][i]);
#endif

#ifdef REVERSE_HORIZONTAL
            SPI.setBitOrder(MSBFIRST);      // reset bitorder
#endif
        }
        digitalWrite(CS, HIGH);
    }
}
//**************************************************************************************************
void char2Arr(unsigned short ch, int PosX, short PosY) { //characters into arr
    int i, j, k, l, m, o1, o2, o3, o4;  //in LEDarr
    PosX++;
    k = ch - 32;                        //ASCII position in font
    if ((k >= 0) && (k < 96))           //character found in font?
    {
        o4 = font1[k][0];                 //character width
        o3 = 1 << (o4 - 2);
        for (i = 0; i < o4; i++) {
            if (((PosX - i <= maxPosX) && (PosX - i >= 0))
                    && ((PosY > -8) && (PosY < 8))) //within matrix?
            {
                o1 = helpArrPos[PosX - i];
                o2 = helpArrMAX[PosX - i];
                for (j = 0; j < 8; j++) {
                    if (((PosY >= 0) && (PosY <= j)) || ((PosY < 0) && (j < PosY + 8))) //scroll vertical
                    {
                        l = font1[k][j + 1];
                        m = (l & (o3 >> i));  //e.g. o4=7  0zzzzz0, o4=4  0zz0
                        if (m > 0)
                            LEDarr[o2][j - PosY] = LEDarr[o2][j - PosY] | (o1);  //set point
                        else
                            LEDarr[o2][j - PosY] = LEDarr[o2][j - PosY] & (~o1); //clear point
                    }
                }
            }
        }
    }
}

void char22Arr(unsigned short ch, int PosX, short PosY) { //characters into arr
    int i, j, k, l, m, o1, o2, o3, o4;  //in LEDarr
    PosX++;
    k = ch - 32;                        //ASCII position in font
    if ((k >= 0) && (k < 96))           //character found in font?
    {
        o4 = font2[k][0];                 //character width
        o3 = 1 << (o4 - 2);
        for (i = 0; i < o4; i++) {
            if (((PosX - i <= maxPosX) && (PosX - i >= 0))
                    && ((PosY > -8) && (PosY < 8))) //within matrix?
            {
                o1 = helpArrPos[PosX - i];
                o2 = helpArrMAX[PosX - i];
                for (j = 0; j < 8; j++) {
                    if (((PosY >= 0) && (PosY <= j)) || ((PosY < 0) && (j < PosY + 8))) //scroll vertical
                    {
                        l = font2[k][j + 1];
                        m = (l & (o3 >> i));  //e.g. o4=7  0zzzzz0, o4=4  0zz0
                        if (m > 0)
                            LEDarr[o2][j - PosY] = LEDarr[o2][j - PosY] | (o1);  //set point
                        else
                            LEDarr[o2][j - PosY] = LEDarr[o2][j - PosY] & (~o1); //clear point
                    }
                }
            }
        }
    }
}

void ScreenPower_On()
{
    ScreenPower_st = 1;
    helpArr_init();
    max7219_init();
    clear_Display();
    refresh_display();
}


/**************************************************************************************************/
void timer50ms() {
    static unsigned int cnt50ms = 0;
    f_tckr50ms = true;
    cnt50ms++;
    if (cnt50ms == 20) {
        f_tckr1s = true; // 1 sec
        cnt50ms = 0;
    }
}


void device_Init()
{
    i2c_Master_init(DEV_8563_I2C_NUM,DEV_8563_SDA_NUM,DEV_8563_SCL_NUM,100000);
    LED_1.LEDC_FadeEN();
}


void setup()
{
    Serial.begin(115200);
    BLINKER_DEBUG.stream(Serial);

    /*点灯函数*/
    Blinker.begin(auth);
    Blinker.attachData(dataRead);
    Blinker.attachHeartbeat(heartbeat);
    Blinker.attachDataStorage(dataStorage);
    Blinker.setTimezone(8.0);
#ifdef TEMP_AND_HUMI_FUNCTION
    BlinkerMIOT.attachQuery(miotQuery); /*小爱同学*/
#else
    BlinkerMIOT.attachPowerState(miotPowerState);
#endif
    
    
    /*注册重配网回调函数BOOT*/
    button.attachLongPressStop(deviceReset);
    Lamp.attach(Lamp_callback);

    /*硬件初始化*/
    device_Init();
    vTaskDelay(30 / portTICK_PERIOD_MS);

    /**/
    pinMode(CS, OUTPUT);
    digitalWrite(CS, HIGH);
    SPI.begin(SCLK, MISO, MOSI, SS);
    void ScreenPower_On();
    tckr.attach(0.05, timer50ms);
    
    /*创建任务*/
    BLINKER_TAST_INIT();/*周期函数*/

    xTaskCreate(Set_Time,           /* Task function. */
                "Set_Time",         /* String with name of task. */
                1024*2,             /* Stack size in bytes. */
                NULL,               /* Parameter passed as input of the task */
                10,                 /* Priority of the task. */
                NULL);              /* Task handle. */

    xTaskCreate(Button_Task,
                "Button_Task",
                1024*2,
                NULL,
                11,
                NULL);

    xTaskCreate(LED_Task,
                "LED_Task",
                1024*2,
                NULL,
                12,
                NULL);            

    xTaskCreate(PCF8563_Task,
                "PCF8563_Task",
                1024*2,
                NULL,
                13,
                NULL);

#ifdef TEMP_AND_HUMI_FUNCTION
    xTaskCreate(SHT30_Task,
                "SHT30_Task",
                1024*2,
                NULL,
                14,
                NULL);
#endif // TEMP_AND_HUMI_FUNCTION

    xTaskCreate(ADC_Task,
                "ADC_Task",
                1024*2,
                NULL,
                15,
                NULL);

    // xTaskCreate(Display_Task,
    //             "Display_Task",
    //             1024*4,
    //             NULL,
    //             16,
    //             NULL);
    

    
}

void loop()
{
    unsigned int sek1 = 0, sek2 = 0, min1 = 0, min2 = 0, std1 = 0, std2 = 0;
    unsigned int sek11 = 0, sek12 = 0, sek21 = 0, sek22 = 0;
    unsigned int min11 = 0, min12 = 0, min21 = 0, min22 = 0;
    unsigned int std11 = 0, std12 = 0, std21 = 0, std22 = 0;

    uint8_t Set_Brightness = 0;

    signed int x = 0; //x1,x2;
    signed int y = 0, y1 = 0, y2 = 0, y3=0;

    bool updown = false;
    unsigned int sc1 = 0, sc2 = 0, sc3 = 0, sc4 = 0, sc5 = 0, sc6 = 0;
    bool f_scrollend_y = false;
    unsigned int f_scroll_x = false;
    bool timee = false;
    
    z_PosX = maxPosX;
    d_PosX = -8;
    //  x=0; x1=0; x2=0;

    refresh_display();
    updown = true;
    if (updown == false) {
        y2 = -9;
        y1 = 8;
    }
    if (updown == true) { //scroll  up to down
        y2 = 8;
        y1 = -8;
    }
    while(1){
        yield();
        if (f_tckr1s == true)        // flag 1sek
        {
            sek1 = rtc.sec % 10;    //秒 个位
            sek2 = rtc.sec / 10;    //秒 十位    
            min1 = rtc.minute % 10; //分 个位
            min2 = rtc.minute / 10; //分 十位
            std1 = rtc.hour % 10;   //时 个位
            std2 = rtc.hour / 10;   //时 十位
            y = y2;                 //scroll updown
            sc1 = 1;
            sek1++;

            // printf("Get Value: %d \r\n",ADC_Light.read_raw);
            // printf("Set Brightness: %d\r\n", ADC_Light.read_raw/256);
            // max7219_set_brightness(ADC_Light.read_raw/256);
            if(ADC_Light.Value_Level == 1) Set_Brightness = 0;
            else if (ADC_Light.Value_Level == 2) Set_Brightness = 2;
            else if (ADC_Light.Value_Level == 3) Set_Brightness = 4;
            else if (ADC_Light.Value_Level == 4) Set_Brightness = 6;
            printf("Set Brightness: %d\r\n", Set_Brightness);
            max7219_set_brightness(Set_Brightness);


            if (sek1 == 10) {
                sc2 = 1;
                sek2++;
                sek1 = 0;
            }
            if (sek2 == 6) {
                min1++;
                sek2 = 0;
                sc3 = 1;
            }
            if (min1 == 10) {
                min2++;
                min1 = 0;
                sc4 = 1;
            }
            if (min2 == 6) {
                std1++;
                min2 = 0;
                sc5 = 1;
            }
            if (std1 == 10) {
                std2++;
                std1 = 0;
                sc6 = 1;
            }
            if ((std2 == 2) && (std1 == 4)) {
                std1 = 0;
                std2 = 0;
                sc6 = 1;
            }

            sek11 = sek12;
            sek12 = sek1;
            sek21 = sek22;
            sek22 = sek2;
            min11 = min12;
            min12 = min1;
            min21 = min22;
            min22 = min2;
            std11 = std12;
            std12 = std1;
            std21 = std22;
            std22 = std2;
            f_tckr1s = false;
                if ((rtc.minute % 10) == 9 || (rtc.minute % 10) == 4)
                {
                    f_scroll_x = true;//滚动开关
                    if (rtc.sec == 45)
                        {
                         timee = true;
                        }
                }
        } // end 1s

        if (f_tckr50ms == true) {
            f_tckr50ms = false;
            if (f_scroll_x == true && timee == true) {
                z_PosX++;
                d_PosX++;
                if (d_PosX == 99)
                    z_PosX = 0;
                if (z_PosX == maxPosX) {
                    f_scroll_x = false;
                    timee = false;
                    d_PosX = -8;
                }   
            }
            if (sc1 == 1) {
                if (updown == 1)
                    y--;
                else
                    y++;
               y3 = y;
               if (y3 > 0) {
                y3 = 0;
                }     
               char22Arr(48 + sek12, z_PosX - 27, y3);
               char22Arr(48 + sek11, z_PosX - 27, y + y1);
                if (y == 0) {
                    sc1 = 0;
                    f_scrollend_y = true;
                }
            }
            else
                char22Arr(48 + sek1, z_PosX - 27, 0);

            if (sc2 == 1) {
                char22Arr(48 + sek22, z_PosX - 23, y3);
                char22Arr(48 + sek21, z_PosX - 23, y + y1);
                if (y == 0)
                    sc2 = 0;
            }
            else
              char22Arr(48 + sek2, z_PosX - 23, 0);

            if (sc3 == 1) {
                char2Arr(48 + min12, z_PosX - 18, y);
                char2Arr(48 + min11, z_PosX - 18, y + y1);
                if (y == 0)
                    sc3 = 0;
            }
            else
                char2Arr(48 + min1, z_PosX - 18, 0);

            if (sc4 == 1) {
                char2Arr(48 + min22, z_PosX - 13, y);
                char2Arr(48 + min21, z_PosX - 13, y + y1);
                if (y == 0)
                    sc4 = 0;
            }
            else
                char2Arr(48 + min2, z_PosX - 13, 0);

              char2Arr(':', z_PosX - 10 + x, 0);

            if (sc5 == 1) {
                char2Arr(48 + std12, z_PosX - 4, y);
                char2Arr(48 + std11, z_PosX - 4, y + y1);
                if (y == 0)
                    sc5 = 0;
            }
            else
                char2Arr(48 + std1, z_PosX - 4, 0);

            if (sc6 == 1) {
                char2Arr(48 + std22, z_PosX + 1, y);
                char2Arr(48 + std21, z_PosX + 1, y + y1);
                if (y == 0)
                    sc6 = 0;
            }
            else
                char2Arr(48 + std2, z_PosX + 1, 0);
            
            /*星期*/
            char2Arr(' ', d_PosX+5, 0);
            char2Arr(WT_arr[rtc.weekday][0], d_PosX - 1, 0);
            char2Arr(WT_arr[rtc.weekday][1], d_PosX - 7, 0);
            char2Arr(WT_arr[rtc.weekday][2], d_PosX - 13, 0);
            char2Arr(WT_arr[rtc.weekday][3], d_PosX - 19, 0);
            /*日*/
            char2Arr(48 + (rtc.day / 10), d_PosX - 24, 0);
            char2Arr(48 + (rtc.day % 10), d_PosX - 30, 0);
            char2Arr(' ', d_PosX - 36, 0);
            /*月*/
            char2Arr(M_arr[rtc.month - 1][0], d_PosX - 41, 0); 
            char2Arr(M_arr[rtc.month - 1][1], d_PosX - 46, 0);
            char2Arr(M_arr[rtc.month - 1][2], d_PosX - 52, 0);
            char2Arr(M_arr[rtc.month - 1][3], d_PosX - 58, 0);
            char2Arr(M_arr[rtc.month - 1][4], d_PosX - 64, 0);
            /*年*/
            char2Arr('2', d_PosX - 69, 0);
            char2Arr('0', d_PosX - 75, 0);
            char2Arr(48 + (rtc.year / 10), d_PosX - 81, 0);
            char2Arr(48 + (rtc.year % 10), d_PosX - 87, 0);
            char2Arr(' ', d_PosX - 93, 0);
            refresh_display(); //alle 50ms
            if (f_scrollend_y == true) {
                f_scrollend_y = false;
            }
        } 
        //end 50ms
        if (y == 0) {
            // do something else
            button.tick();
        }
        vTaskDelay(1 / portTICK_PERIOD_MS);
    }
    
    // Wait
    // delay(1000);
}

